
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;

using Swaf;

namespace Swaf.Container
{
	public delegate void mapChanged(string key, object val);

	public class ServerStateFlexiMap : IMap
	{
		protected static string s_clearKey = "_____clear_____";
		protected static string s_fullImageKey = "_____fullImage_____";
		protected static string s_multiXmlKey = "_____multiXml_____";
		protected static string s_publishXmlKey = "_____pubXml_____";
		protected static string s_publishMapKey = "_____pubMap_____";

		protected FlexiMap m_innerMap = new FlexiMap();
		protected IServerStateManager m_stateMgr = null;
		protected string m_id = new Swaf.BGuid.Guid().ToString();
		protected string m_lastSyncId = null;

		public ServerStateFlexiMap(string id, string multiCastGroupIP, int portNum, int ttlDistance, string cryptoKeyName)
		{
			m_stateMgr = new UdpServerStateManager(id, multiCastGroupIP, portNum, ttlDistance, cryptoKeyName);
			m_stateMgr.registerMessageHandler(new processMessage(this.updateHandler));
		}

		public event mapChanged Changed;

		protected void updateHandler(string key, object data)
		{
			if (!key.StartsWith(m_id))
			{
				key = key.Substring(m_id.Length);
				bool changeMsg = true;

				if (key == s_clearKey)
					m_innerMap.Clear();
				else if (key == s_fullImageKey)
				{
					if (m_lastSyncId != null)
					{
						FlexiMap innerMap = data as FlexiMap;
						if (innerMap != null)
							m_innerMap = innerMap;
						m_lastSyncId = null;
					}
					else
						changeMsg = false;
				}
				else if (key == s_multiXmlKey)
					m_innerMap.populateFromXml(data.ToString());
				else if (key == s_publishXmlKey)
				{
					changeMsg = false;
					m_stateMgr.sendMessage(m_id + s_multiXmlKey, m_innerMap.Xml);
				}
				else if (key == s_publishMapKey)
				{
					changeMsg = false;
					m_stateMgr.sendMessage(m_id + s_fullImageKey, m_innerMap);
				}
				else
					m_innerMap.put(key, data);

				if (Changed != null && changeMsg)
					Changed(key, data);
			}
		}

		public void sync()
		{
			m_lastSyncId = new Swaf.BGuid.Guid().ToString();
			m_stateMgr.sendMessage(m_id + s_publishMapKey, m_lastSyncId);
		}
		#region INameAddressSupport Members

		public void put(string nameAddress, object val)
		{
			m_innerMap.put(nameAddress, val);
			m_stateMgr.sendMessage(m_id+nameAddress, val);
		}

		public void put(string nameAddress, object val, object extraInfo)
		{
			m_innerMap.put(nameAddress, val, extraInfo);
			m_stateMgr.sendMessage(m_id + nameAddress, val);
		}

		public object get(string nameAddress, params object[] infoArgs)
		{
			return m_innerMap.get(nameAddress, infoArgs);
		}

		public object get(string nameAddress, object oneArg)
		{
			return m_innerMap.get(nameAddress, oneArg);
		}

		public object get(string nameAddress)
		{
			return m_innerMap.get(nameAddress);
		}

		public bool isGetOnly
		{
			get { return false; }
		}

		public XmlSerializationSupport SerializationSupport
		{
			get { return m_innerMap.SerializationSupport; }
		}

		public string Xml
		{
			get { return m_innerMap.Xml; }
		}

		public string getXml(string options)
		{
			return m_innerMap.getXml(options);
		}

		public bool containsField(string nameAddress)
		{
			return m_innerMap.containsField(nameAddress);
		}

		#endregion

		#region IDictionary Members

		public void Add(object key, object value)
		{
			m_innerMap.Add(key, value);
			m_stateMgr.sendMessage(m_id + key.ToString(), value);
		}

		public void Clear()
		{
			m_innerMap.Clear();
			m_stateMgr.sendMessage(m_id + s_clearKey, "");
		}

		public bool Contains(object key)
		{
			return m_innerMap.Contains(key);
		}

		public IDictionaryEnumerator GetEnumerator()
		{
			return m_innerMap.GetEnumerator();
		}

		public bool IsFixedSize
		{
			get { return false; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public ICollection Keys
		{
			get { return m_innerMap.Keys; }
		}

		public void Remove(object key)
		{
			m_innerMap.Remove(key);
		}

		public ICollection Values
		{
			get { return m_innerMap.Values; }
		}

		public object this[object key]
		{
			get
			{
				return m_innerMap[key];
			}
			set
			{
				m_innerMap[key] = value;
				m_stateMgr.sendMessage(m_id + key.ToString(), value);
			}
		}

		#endregion

		#region ICollection Members

		public void CopyTo(Array array, int index)
		{
			m_innerMap.CopyTo(array, index);
		}

		public int Count
		{
			get { return m_innerMap.Count; }
		}

		public bool IsSynchronized
		{
			get { return false; }
		}

		public object SyncRoot
		{
			get { return this; }
		}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			return m_innerMap.GetEnumerator();
		}

		#endregion
	}
}
